package com.mytime.resources;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.restlet.data.CharacterSet;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;

import com.google.appengine.api.datastore.KeyFactory;
import com.mytime.database.Category;
import com.mytime.database.Event;
import com.mytime.database.PMF;
import com.mytime.database.Timetable;
import com.mytime.database.Venue;
import com.mytime.util.Functions;
import com.mytime.util.WSQuery;

public class AllEvents extends ServerResource {
	
    /**
     * Handles a GET HTTP request. 
     * @return All events whose start time is after current time.
     * @throws ResourceException
     */
	@Get
	public Representation getAllEvents(Representation entity) throws Exception {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		JSONObject eventsObject = new JSONObject();
		JSONArray eventsArray = new JSONArray();

		int startTime = 0;
		String categories = "";
		String region = "";
		
		//Get parameter from request
		System.out.println(this.getRequest());
		System.out.println(this.getRequestAttributes());
		System.out.println(this.getRequestEntity());
		
		if (getQuery().getValues("startTime") != null)
			startTime = Integer.parseInt(getQuery().getValues("startTime"));
		if (getQuery().getValues("region") != null)
			region = getQuery().getValues("region");
		if (getQuery().getValues("categories") != null)
			categories = getQuery().getValues("categories");
		 
		System.out.println(categories);
		String categoriesFromParameters[] = categories.split("\\|");
		ArrayList<String> categoriesList = new ArrayList<String>();
		
		for (int i = 0; i < categoriesFromParameters.length; i++) {
			categoriesList.add(categoriesFromParameters[i]);
		}
		
		try {
			//Get events based on the given parameters
			List<Event> events = WSQuery.getAllEvents(pm, startTime, region, categoriesList);

			eventsArray = WSQuery.getEventsArray(pm, events);
			eventsObject.put("events", eventsArray);
			return getRepresentation(eventsObject);
			
		} catch(Exception e) {
			eventsObject.put("error", e.getMessage());
			return getRepresentation(eventsObject);
		}

	}
	
    /**
     * Adds one or more events in the system. 
     * @param entity
     * @throws JSONException 
     * @throws IOException 
     */
	@Post
	public Representation acceptRepresentation(Representation entity) throws JSONException, IOException {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		JsonRepresentation rep = new JsonRepresentation(entity);
		JSONObject result = new JSONObject();
		int added = 0;
		
        try {
        	//Getting data
			JSONObject data = rep.getJsonObject();
			JSONArray events = data.getJSONArray("events");
			
			for (int i = 0; i < events.length(); i++) {
				JSONObject jsonobj = events.getJSONObject(i);
				
				String eventName = jsonobj.getString("name");
				String strKey = Functions.removeSpecialCharacters(eventName).
						toLowerCase().replaceAll(" ", "_");
				
				//Verify if event already exists
				Query eventExists = pm.newQuery(Event.class);
				eventExists.setFilter("strKey == \'" + strKey + "\'");
				@SuppressWarnings("unchecked")
				List<Event> eList = (List<Event>) eventExists.execute();
				
				Event event = new Event();
				if (eList.iterator().hasNext()) {
					event = eList.iterator().next();
					event.updateValues(jsonobj);
				} else 
					event = new Event(jsonobj);
				
				//Creating Event object and adding its properties
				String eventKey = KeyFactory.keyToString(event.getKey());
				
				//Save category
				if (jsonobj.has("category")) {
					Category category = new Category();
					category.setName(jsonobj.getString("category"));
					category.setId(Functions.removeSpecialCharacters(jsonobj.getString("category")).
							toLowerCase().replaceAll(" ", "_"));

					event.setCategory(category.getId());
					
					pm.makePersistent(category);
				}
				
				//Event venues
				if (jsonobj.has("venues")) {
					JSONArray venues = jsonobj.getJSONArray("venues");
					
					for (int k = 0; k < venues.length(); k++) {
						JSONObject jsonVenue = venues.getJSONObject(k);
						
						Venue eVenue = new Venue(jsonVenue);
						String encodedVenueKey = eVenue.getEncodedKey();

						//Add event to Venue List
						eVenue.addEvent(event.getKey());
						
						//Add Venue to system
						pm.makePersistent(eVenue);
						
						//Add Venue's key to the event
	    				event.addVenue(eVenue.getKey());
	    				
	    				//Get showtimes in this Venue
	    				if (jsonVenue.has("showtimes")	) {
	    					JSONArray showtimes = jsonVenue.getJSONArray("showtimes");
	    					
	    					for (int s = 0; s < showtimes.length(); s++) {
	    						JSONObject timeObj = showtimes.getJSONObject(s);
	    						
	    						Timetable entry = new Timetable();
	    						entry.setEventId(eventKey);
	    						entry.setVenueId(encodedVenueKey);
	    						entry.setStartTime(timeObj.getString("startTime"));
	    						entry.setEndTime(timeObj.getString("endTime"));
	    						
	    						pm.makePersistent(entry);
	    					}
	    				}
					}
					
				}

				try {	
					//Add Event
    				pm.makePersistent(event);
	    			added += 1;
    				
    			} catch(Exception e) {
    				e.printStackTrace();
    				result.put("error", e.getMessage());
    			
    			}	    			   			
			}
			
        } catch (JSONException e) {
			e.printStackTrace();
			result.put("error", e.getMessage());
			
		} finally {
	        pm.close();
    	}
        
        result.put("added", added);
        
        return getRepresentation(result);
	}

	/**
	 * Returns the JSON representation for a given JSON object.
	 * */
    private Representation getRepresentation(JSONObject jsonObject) {
    	JsonRepresentation jr = new JsonRepresentation(jsonObject);
    	jr.setCharacterSet(CharacterSet.UTF_8);
    	
    	return jr;
    }    

}
